//都是从安全性考虑 ts兼容性 兼容性是在把一个变量赋值给另一个变量才产生的
//1:基本类型的兼容性
let v1!: string | number;
let v2!: string | number | boolean;

v2 = v1;//少的类型可以赋予给多的 js中typeof返回的是一个字符串类型


//2.接口类型兼容 (只要多的类型 可以赋予给少的) 鸭子类型检测（不关心内容 只看长的一不一样）
interface A1 {
    name: string,
    age: number
}
interface A2 {
    name: string,
    age: number,
    address: number
}

let a1!: A1
let a2!: A2
a1 = a2

//3.函数的兼容性 参数 返回值（少的可以赋值给多的）
let sum1 = (a: string, b: string) => { }
let sum2 = (a: string) => { }

//之前写过一个map方法 我定义的时候 有2个参数 但是用户使用的时候 只是用了一个
sum1 = sum2;//定义了a,b 但是你只用一个c 也可以的


//类的类型 兼容性检测是符合鸭子检测的（实例 只要实例一样 那就是一个东西）
//特殊情况 就是类中如果带了private protected 就是不一个东西了（不兼容了）
class Person {
    public name = "张三"
}
class Animal {
    public name = "李四"
}

let p!: Person
let a!: Animal

p = a;
a = p;

//枚举永远不兼容 泛型是否兼容看最终的结果
enum E1 { }
enum E2 { }
// let e1!:E1;
// let e12: E2;
// e1 == e2

//针对函数的抽象概念 参数是逆变 和返回值是协变可以返回儿子（可以传父返子） 参数的父子关系
//如果配置ts的话 可以设置成双向协变 (这个方式不考虑) strict:false
class GrandParent {
    house!: string
}
class Parent extends GrandParent {
    house!: string
}
class Son extends Parent {
    play!: string
}
function getFn(cb: (val: Parent) => void) {
}

getFn((val: GrandParent) => new Son)

//这个地方的val 相当于赋予给下面的函数
//这个val是标识类型的
function getFn1(cb: (val: number | boolean) => string | boolean) {
    cb(true);//这个是实参
}
//传父：多的就是父
//这个val 是形参 getFn1传递的参数是一个函数 是实参
getFn1((val: number | string | boolean) => "")

export { }